﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Bundler.Tests
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class BundleTests
    {
        public BundleTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void CreateCssMinifyBundle()
        {
            var css = new Bundle("~/CssMinify", typeof(CssMinify));
            css.AddFile("~/Content/Site.css");
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CssMinify");
            Assert.IsTrue(isInTable);

            TestResponse(BundleTable.Responses["~/CssMinify"]);
        }

        [TestMethod]
        public void CreateCssMinifyImageEmbedBundle()
        {
            var css = new Bundle("~/CssMinifyImageEmbed", typeof(CssMinifyImageEmbed));
            css.AddFile("~/Content/Embed.css");
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CssMinifyImageEmbed");
            Assert.IsTrue(isInTable);

            var response = BundleTable.Responses["~/CssMinifyImageEmbed"];
            TestResponse(response);

            var containsBase64EmbeddedImage = response.Content.Contains("data:image/png;base64,");
            Assert.IsTrue(containsBase64EmbeddedImage);
        }

        [TestMethod]
        public void CreateCssMinifySpriteEmbedBundle()
        {
            var css = new Bundle("~/CssMinifySpriteEmbed", typeof(CssMinifySpriteEmbed));
            css.AddFile("~/Content/Sprite.css");
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CssMinifySpriteEmbed");
            Assert.IsTrue(isInTable);

            var response = BundleTable.Responses["~/CssMinifySpriteEmbed"];
            TestResponse(response);

            var containsBase64EmbeddedImage = response.Content.Contains("data:image/png;base64,");
            Assert.IsTrue(containsBase64EmbeddedImage);

            var containsSpriteClass = response.Content.Contains(".sprite{");
            Assert.IsTrue(containsSpriteClass);

            var containsCrossSpriteClass = response.Content.Contains(".img-cross.sprite{");
            Assert.IsTrue(containsCrossSpriteClass);
        }

        public void TestResponse(BundleResponse response)
        {
            Assert.IsNotNull(response);
            Assert.IsTrue(response.Processed);
            Assert.IsNotNull(response.RequestAction);

            var aliasIsGreaterThanZero = response.Alias > 0;
            Assert.IsTrue(aliasIsGreaterThanZero);

            var contentIsNotNullOrWhiteSpace = !String.IsNullOrWhiteSpace(response.Content);
            Assert.IsTrue(contentIsNotNullOrWhiteSpace);
        }

        [TestMethod]
        public void CreateJsMinifyBundle()
        {
            var css = new Bundle("~/CreateJsMinifyBundle", typeof(JsMinify));
            css.AddFile("~/Scripts/jquery-1.8.2.js");
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CreateJsMinifyBundle");
            Assert.IsTrue(isInTable);

            TestResponse(BundleTable.Responses["~/CreateJsMinifyBundle"]);
        }

        [TestMethod]
        public void CssMinifyRawContent()
        {
            const string content = "body\n\r{\n\r\tbackground-color: #FFFFFF;\n\r\tcolor: #000000;\n\r}\n\r\n\r.clear\n\r{\n\r\tclear: both;\n\r}";
            var css = new Bundle("~/CssMinifyRawContent", typeof(CssMinify));
            css.AddContent(content);
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CssMinifyRawContent");
            Assert.IsTrue(isInTable);

            var response = BundleTable.Responses["~/CssMinifyRawContent"];
            var minifiedContentIsSmallerThanOriginal = content.Length > response.Content.Length;
            Assert.IsTrue(minifiedContentIsSmallerThanOriginal);

            TestResponse(response);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException), "bundle")]
        public void AddNullBundle()
        {
            BundleTable.Add(null);
        }

        [TestMethod]
        public void CssMinifyWithNoOptimization()
        {
            var options = new BundleOptions()
            {
                EnableOptimizations = false
            };

            var css = new Bundle("~/CssMinifyWithNoOptimization", typeof(CssMinify), options);
            css.AddFile("~/Content/Site.css");
            BundleTable.Add(css);

            var isInTable = BundleTable.IsInTable("~/CssMinifyWithNoOptimization");
            Assert.IsTrue(isInTable);

            TestResponse(BundleTable.Responses["~/CssMinifyWithNoOptimization"]);
        }

        [TestMethod]
        public void DeferredJsBundle()
        {
            var options = new BundleOptions()
            {
                Js = {DeferLoading = true}
            };
            var js = new Bundle("~/DeferredJsBundle", typeof (JsMinify), options);
            js.AddFile("~/Scripts/jquery-1.8.2.js");
            BundleTable.Add(js);
            var result = BundleTable.RenderHtmlFor(@"~/DeferredJsBundle");
        }

        [TestMethod]
        public void RenderHtmlForBundle()
        {
            var css = new Bundle("~/RenderHtmlForBundle", typeof(JsMinify));
            css.AddFile("~/Scripts/jquery-1.8.2.js");
            BundleTable.Add(css);

            var htmlString = BundleTable.RenderHtmlFor("~/RenderHtmlForBundle");
            Assert.IsNotNull(htmlString);
            var htmlStringOutput = htmlString.ToHtmlString();
            Assert.IsTrue(!String.IsNullOrWhiteSpace(htmlString.ToHtmlString()));
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException), "virtualPath")]
        public void RenderHtmlForNullBundle()
        {
            BundleTable.RenderHtmlFor(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ApplicationException), "~/someRandomName not found")]
        public void RenderHtmlForInvalidBundle()
        {
            BundleTable.RenderHtmlFor("~/someRandomName");
        }
    }
}
